#include "../../Coroutine/Fiber.hpp"
#include "../../base/BaseLog.hpp"
#include "../../Coroutine/Thread.hpp"

#include <cassert>
#include <memory>
#include <thread>
#include <utility>
#include <vector>

using namespace DBServer::coroutine;
void fiber_1() {
    auto cur = Fiber::GetThis();
    debug("fiber(%ld): begin fiber_1\n", cur->get_id());

    assert(cur->get_state() == FiberState::EXEC);
    Fiber::Yield();
    assert(cur->get_state() == FiberState::EXEC);

    debug("fiber(%ld): after fiber_1\n", cur->get_id());
}

void fiber_2() {
    auto cur = Fiber::GetThis();
    debug("fiber(%ld): begin fiber_2\n", cur->get_id());

    assert(cur->get_state() == FiberState::EXEC);
    Fiber::Yield();
    assert(cur->get_state() == FiberState::EXEC);

    debug("fiber(%ld): after fiber_2\n", cur->get_id());
}

void test() {
    Thread::MainThread();

    // 初始化主协程
    Fiber::GetThis();

    //info("begin test!\n");

    Fiber::ptr fiber1 = std::make_shared<Fiber>(fiber_1);

    Fiber::ptr fiber2 = std::make_shared<Fiber>(fiber_2);

    info("--------------------------------------------\n");
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber1->get_id(), fiber1.use_count());
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber2->get_id(), fiber2.use_count());
    info("--------------------------------------------\n");

    {
        auto cur = Fiber::GetThis();
        //info("main fiber(%ld)\n", cur->get_id());
    }

    fiber1->resume();
    fiber2->resume();

    info("--------------------------------------------\n");
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber1->get_id(), fiber1.use_count());
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber2->get_id(), fiber2.use_count());
    info("--------------------------------------------\n");

    {
        //auto cur = Fiber::GetThis();
        //info("main fiber(%ld)\n", cur->get_id());
    }

    fiber1->set_state(DBServer::coroutine::FiberState::READY);
    fiber2->set_state(DBServer::coroutine::FiberState::READY);

    fiber2->resume();
    fiber1->resume();

    assert(fiber1->get_state() == FiberState::TERM);
    assert(fiber2->get_state() == FiberState::TERM);

    info("--------------------------------------------\n");
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber1->get_id(), fiber1.use_count());
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber2->get_id(), fiber2.use_count());
    info("--------------------------------------------\n");

    fiber1->reset(
        []
        {
            debug("begin reset fiber1");
            Fiber::Yield();
            debug("end reset fiber1\n");
        });

    fiber2->reset(
        []()
        {
            debug("beign reset fiber2\n");
            Fiber::Yield();
            debug("end reset fiber2\n");
        });

    fiber1->resume();
    fiber2->resume();

    info("--------------------------------------------\n");
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber1->get_id(), fiber1.use_count());
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber2->get_id(), fiber2.use_count());
    info("--------------------------------------------\n");

    fiber1->set_state(FiberState::READY);
    fiber2->set_state(FiberState::READY);

    fiber2->resume();
    fiber1->resume();

    info("--------------------------------------------\n");
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber1->get_id(), fiber1.use_count());
    debug("thead(%ld) : fiber(%d) count(%d)\n", Thread::ThreadId(), fiber2->get_id(), fiber2.use_count());
    info("--------------------------------------------\n");

    fiber1.reset();
    fiber2.reset();

    info("finish tset!\n");
}


int main(int argc, const char** argv) {
    std::vector<std::thread> pool;
    for (int i = 0; i < 1; i ++ )
    {
        pool.push_back(std::move(Thread::CreatThread(test)));
    }

    for (auto &t : pool) 
    {
        t.join();
    }

    return 0;
}